﻿using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Threading.Tasks;
using TyMES.Communication;
using TyMES.Communication.Request;
using TyMES.Model.BaseInformation;
using WalkingTec.Mvvm.Core;
using Newtonsoft.Json;
using static TyMES.Communication.FactoryAPIBase;
using static TyMES.Communication.Request.UploadProductDataRequset;
using TyMES.Model.GetData;
using TyMES.Model.Record;
using TyMES.TemporaryClass;
using Azure;
using TyMES.Communication.Response;

namespace TyMES.Services
{
    public class ProductDataService
    {
        private readonly ILogger logger;
        private readonly IConfiguration configuration;
        private readonly HttpService httpService;
        private readonly IServiceScope serviceScope;
        private readonly WTMContext context;
        private string factoryCode;
        private string lineCode;
        private string mesIP;
        private string mesPort;
        private StationServices passStationService;
        public ProductDataService(ILogger<ProductDataService> logger, IConfiguration configuration, HttpService httpService, IServiceScopeFactory serviceScopeFactory, StationServices passStationService)
        {
            this.logger = logger;
            this.configuration = configuration;
            this.httpService = httpService;
            this.serviceScope = serviceScopeFactory.CreateScope();
            var sp = this.serviceScope.ServiceProvider;
            this.context = sp.GetRequiredService<WTMContext>();
            factoryCode = configuration["FactoryCode"];
            mesIP = configuration["MESIP"];
            mesPort = configuration["MESPORT"];
            lineCode = configuration["LineCode"];
            this.passStationService = passStationService; 
        }

        public async Task GetAllDataTemplate(string product, string line, Order_Model order)
        {
            string url = "http://" + mesIP + ":" + mesPort + configuration["ROUTEBOM"];
            var route = await passStationService.GetRoute(product, order);
            if (route == null) return;
            var routeOperations = GetRouteOperation(route.RouteCode, order.OrderCode);
            foreach (RouteOperation routeOperation in routeOperations)
            {
                var pdTemplate = await GetPDTemplate(routeOperation);
                if (pdTemplate != null)
                {
                    foreach (var template in pdTemplate.Data)
                    {
                        template.UniqueCode = order.OrderCode;
                        await AddorUpdateFMESDataTemplate(template);

                    }
                }
                //await SynchronousLMESTemplate(routeOperation.OperationCode);
                await SyncBadCodeTemplate(routeOperation.OperationCode);
                await SyncStations(line, url, routeOperation);

            }
        }

        public async Task SyncBadCodeTemplate(string operationCode)
        {
            try
            {
                BadCodeTemplateRequest request = new BadCodeTemplateRequest("Base008_BadCode", "TH13", operationCode, "");
                string psd = JsonConvert.SerializeObject(request);
                string value = await httpService.PostDataAsync("http://"+mesIP+":"+mesPort+"/api/base/Base_Information", psd);
                BadCodeResponse response = JsonConvert.DeserializeObject<BadCodeResponse>(value);
                List<BadCodeTemplate> badCodeTemplate =await PackBadCode(response.data);
                context.DC.Set<BadCodeTemplate>().AddRange(badCodeTemplate);
                context.DC.SaveChanges();
                return;
            }
            catch (Exception ex)
            {
                return;
            }
            
        }

        private async Task<List<BadCodeTemplate>> PackBadCode(List<BadCodeData> datas)
        {
            List<BadCodeTemplate> badCodes = new List<BadCodeTemplate>();
            foreach(BadCodeData data in datas)
            {
                BadCodeTemplate badCodeTemplate = new BadCodeTemplate();
                badCodeTemplate.BadCode = data.badCode;
                badCodeTemplate.BadName = data.badName;
                badCodeTemplate.BadTypeCode = data.badTypeCode;
                badCodeTemplate.BadTypeName = data.badTypeName;
                badCodeTemplate.DataStatus = data.dataStatus;
                badCodeTemplate.EnableStatus = data.enableStatus;
                badCodeTemplate.Field1 = data.field1;
                badCodeTemplate.Field2 = data.field2;
                badCodeTemplate.Field3 = data.field3;
                badCodeTemplate.Field4 = data.field4;
                badCodeTemplate.Field5 = data.field5;
                badCodeTemplate.OperationCode = data.operationCode;
                badCodes.Add(badCodeTemplate);
            }
            
            return badCodes;
        }
        private async Task SyncStations(string line, string url, RouteOperation routeOperation)
        {
            OperationStation operationStation = new OperationStation("Base011_OperationStation", "TH13", routeOperation.OperationCode, "");
            string psd = JsonConvert.SerializeObject(operationStation);
            string value = await httpService.PostDataAsync(url, psd);
            var result = System.Text.Json.JsonSerializer.Deserialize<ApiResponse<StationInfo>>(value);
            Station station = new Station();
            for (int i = 0; i < result.Data.Count; i++)
            {
                var thisStation = context.DC.Set<Station>().Where(x=>x.StationCode== result.Data[i].stationCode).ToList();
                if (thisStation.Count > 0)
                {
                    thisStation[0].StationCode = result.Data[i].stationCode;
                    thisStation[0].StationName = result.Data[i].stationName;
                    thisStation[0].LineCodeId = line;
                }
                else
                {
                    station.StationCode = result.Data[i].stationCode;
                    station.StationName = result.Data[i].stationName;
                    station.LineCodeId = line;
                    context.DC.Set<Station>().Add(station);
                }
                
            }
            context.DC.SaveChanges();
        }

        public record OperationStation(string serviceId, string factoryCode, string operationCode, string stationCode);

        public class StationInfo
        {
            public string operationCode { get; set; }
            public string operationId { get; set; }
            public string operationName { get; set; }
            public string stationCode { get; set; }
            public string stationId { get; set; }
            public string stationName { get; set; }
        }
        public List<RouteOperation> GetRouteOperation(string routecode, string ordercode)
        {
            var operations = context.DC.Set<RouteOperation>().Where(x => x.RouteNumber == routecode && x.OrderCode == ordercode).ToList();
            return operations;
        }


        public async Task<FactoryAPIBase.ApiResponse<ProductDataTemplates>> GetPDTemplate(RouteOperation routeOperation)
        {
            GetPDTemplateRequest request =
                new GetPDTemplateRequest(routeOperation.OperationCode);
            string url = "http://" + mesIP + ":" + mesPort + configuration["PDTemplate"];
            string psd = System.Text.Json.JsonSerializer.Serialize(request);
            string value = await httpService.PostDataAsync(url, psd);
            ApiResponse<ProductDataTemplates> response = JsonConvert.DeserializeObject<ApiResponse<ProductDataTemplates>>(value);
            return response;
        }

        public async Task AddorUpdateFMESDataTemplate(ProductDataTemplates productDataTemplate)
        {
            var check = context.DC.Set<ProductDataTemplates>().FirstOrDefault(x =>
                x.OperationCode == productDataTemplate.OperationCode &&
                x.TemplateCode == productDataTemplate.TemplateCode && 
                x.ParamCode == productDataTemplate.ParamCode &&
                x.UniqueCode == productDataTemplate.UniqueCode);
            if (check != null) check = productDataTemplate;
            else context.DC.Set<ProductDataTemplates>().Add(productDataTemplate);
            await context.DC.SaveChangesAsync();
        }



        public async Task SynchronousLMESTemplate(string operationCode)
        {
            var listlength = context.DC.Set<ProductDataTemplates>().Where(x => x.OperationCode == operationCode)?.Count();
            var productData = new List<ProductDataTemplates>();
            List<LMESProductDataTemplate> lmesdatatemplates = new List<LMESProductDataTemplate>();
            if (listlength != 0)
            {
                for (int i = 1; i < listlength + 1; i++)
                    productData.Add(context.DC.Set<ProductDataTemplates>()
                        .FirstOrDefault(x => x.OperationCode == operationCode && x.Sort == i));
                if (productData.Count > 0)
                {
                    await AddorUpdateLMESDataTemplates(productData);
                }
            }
        }
        public async Task AddorUpdateLMESDataTemplates(List<ProductDataTemplates> productData)
        {
            int j = 0;
            foreach (var VARIABLE in productData)
            {
                if (VARIABLE == null) return;
                if (!(VARIABLE.ParamRange1 == "" && VARIABLE.ParamRange2 == "" && VARIABLE.StandardValue == ""))
                {
                    LMESProductDataTemplate template = context.DC.Set<LMESProductDataTemplate>().FirstOrDefault(x => x.TemplateCode == VARIABLE.TemplateCode && x.Sort == VARIABLE.Sort);
                    if (template == null)
                    {
                        LMESProductDataTemplate lmesDataTemplate = new LMESProductDataTemplate();
                        lmesDataTemplate = MapTempalte(VARIABLE);
                        lmesDataTemplate.Actualsort = j;
                        context.DC.Set<LMESProductDataTemplate>().Add(lmesDataTemplate);
                    }
                    else
                    {
                        template = MapTempalte(VARIABLE);
                        template.Actualsort = j;
                    }
                    j++;
                    await context.DC.SaveChangesAsync();
                }
            }
        }

        public LMESProductDataTemplate MapTempalte(ProductDataTemplates productDataTemplate)
        {
            LMESProductDataTemplate lmesDataTemplate = new LMESProductDataTemplate();
            lmesDataTemplate.DataStatus = productDataTemplate.DataStatus;
            lmesDataTemplate.EnableStatus = productDataTemplate.EnableStatus;
            lmesDataTemplate.EquCode = productDataTemplate.EquCode;
            lmesDataTemplate.EquName = productDataTemplate.EquName;
            lmesDataTemplate.FactoryCode = productDataTemplate.FactoryCode;
            lmesDataTemplate.OperationCode = productDataTemplate.OperationCode;
            lmesDataTemplate.ParamCode = productDataTemplate.ParamCode;
            lmesDataTemplate.ParamCodeKey = productDataTemplate.ParamCodeKey;
            lmesDataTemplate.ParamName = productDataTemplate.ParamName;
            lmesDataTemplate.ParamNameKey = productDataTemplate.ParamNameKey;
            lmesDataTemplate.ParamRange1 = productDataTemplate.ParamRange1;
            lmesDataTemplate.ParamRange2 = productDataTemplate.ParamRange2;
            lmesDataTemplate.ParamUnit = productDataTemplate.ParamUnit;
            lmesDataTemplate.ParamValueKey = productDataTemplate.ParamValueKey;
            lmesDataTemplate.Sort = productDataTemplate.Sort.Value;
            lmesDataTemplate.StandardValue = productDataTemplate.StandardValue;
            lmesDataTemplate.StationCode = productDataTemplate.StationCode;
            lmesDataTemplate.TemplateCode = productDataTemplate.TemplateCode;
            lmesDataTemplate.UniqueCode = productDataTemplate.UniqueCode;
            return lmesDataTemplate;
        }

        public List<ProduceDataRecord> MapFromLMESTemplate(ProduceDataRecord data)
        {
            List<ProduceDataRecord> lmesData = new List<ProduceDataRecord>();
            var ordercode = context.DC.Set<TrayBindVSN>().SingleOrDefault(x => x.VSN == data.SN).OrderCode;
            var template = context.DC.Set<LMESProductDataTemplate>().
                Where(x => x.StationCode == data.StationCode
                    && x.UniqueCode==ordercode).ToList();
            var datalist = data.Data.Split("*");
            var resultlist = data.Result.Split("*");
            var zipped = template.Select((t, index) => (t, data: datalist[index], result: resultlist[index]));
            foreach (var item in zipped)
            {
                var equipmentData = GetEquipmentDataFromSCADA(item);
                lmesData.Add(equipmentData);
            }
            return lmesData;
        }

        public ProduceDataRecord GetEquipmentDataFromSCADA((LMESProductDataTemplate t, string data, string result) item)
        {
            ProduceDataRecord equipmentData = new ProduceDataRecord();
            equipmentData.Data = item.data;
            if (double.TryParse(item.data, out double value))
            {
                if (double.TryParse(item.t.ParamRange1, out double para1) && double.TryParse(item.t.ParamRange2, out double para2))
                {
                    if (value > para1 && value < para2)
                        equipmentData.Result = "0"; // 0为合格
                    else
                        equipmentData.Result = "1";
                }
                else if (!(double.TryParse(item.t.ParamRange1, out double para3)) && double.TryParse(item.t.ParamRange2, out double para4))
                {
                    if (value < para4)
                        equipmentData.Result = "0"; // 0为合格
                    else
                        equipmentData.Result = "1";
                }
                else if (double.TryParse(item.t.ParamRange1, out double para5) && !(double.TryParse(item.t.ParamRange2, out double para6)))
                {
                    if (value > para5)
                        equipmentData.Result = "0"; // 0为合格
                    else
                        equipmentData.Result = "1";
                }
            }
            else if (item.t.StandardValue != null)
            {
                if (item.result == item.t.StandardValue)
                    equipmentData.Result = "0"; // 0为合格
                else
                    equipmentData.Result = "1";
            }
            equipmentData.DataName = item.t.ParamName;
            return equipmentData;
        }






        public async Task UploadProductData2FMES(string stationcode, string SN)
        {
            StationLogRecord stationLog = new StationLogRecord();
            UploadProductDataRequset request =
                MapToRequset(context.DC.Set<LMESProductDataTemplate>().Where(x => x.StationCode == stationcode).ToList(), SN);
            ApiResponse response = UploadProductData(request).Result;
            if (response.Code == "000000")
            {
                stationLog.LogType = "good";
                stationLog.Log = "生产数据上传成功" + SN + ":" + response.Data + ":" + response.Mesg;
            }
            else
            {
                stationLog.LogType = "bad";
                stationLog.Log = "生产数据上传失败" + SN + ":" + response.Data + ":" + response.Mesg;
            }
            await context.DC.Set<StationLogRecord>().AddAsync(stationLog);
        }

        public UploadProductDataRequset MapToRequset(List<LMESProductDataTemplate> equipmentData, string SN)
        {
            List<InspectionData> inspectionData = new List<InspectionData>();
            var a = context.DC.Set<ProduceDataRecord>().Where(x =>
                x.StationCode == equipmentData[0].StationCode && x.SN == SN && x.SqlFlag != true).ToList();
            foreach (var items in equipmentData)
            {
                var inspect = Map(items);
                inspect.SnNumber = SN;
                inspect.DataStatus = a?.FirstOrDefault(x => x.Actualsort == items.Actualsort)?.Result;
                inspectionData.Add(inspect);
            }
            UploadProductDataRequset request = new UploadProductDataRequset(inspectionData);
            return request;
        }
        public InspectionData Map(LMESProductDataTemplate template)
        {
            InspectionData inspectionData = new InspectionData();

            inspectionData.FactoryCode = template.FactoryCode;
            inspectionData.LineCode = context.DC.Set<Station>().FirstOrDefault(x => x.StationCode == template.StationCode)?.LineCodeId;
            inspectionData.StationCode = template.StationCode;
            inspectionData.OperationCode = template.OperationCode;
            inspectionData.ParamCode = template.ParamCode;
            inspectionData.ParamName = template.ParamName;
            inspectionData.StandardValue = template.StandardValue;
            inspectionData.ParamRange1 = template.ParamRange1;
            inspectionData.ParamRange2 = template.ParamRange2;
            inspectionData.DataStatus = template.DataStatus;
            inspectionData.AddUserCode = "";
            inspectionData.MachineCode = template.EquCode;
            return inspectionData;
        }
        public async Task<FactoryAPIBase.ApiResponse> UploadProductData(UploadProductDataRequset request)
        {
            if (request == null)
            {
                string url = "http://" + mesIP + ":" + mesPort + configuration["UploadProductData"];
                string psd = JsonConvert.SerializeObject(request);
                string value = await httpService.PostDataAsync(url, psd);
                ApiResponse response = JsonConvert.DeserializeObject<ApiResponse>(value);
                return response;
            }
            return null;
        }
    }
}
